module arithmetic_unit(
  input [6:0] op,
  input [63:0] src1,
  input [63:0] src2,
  input [63:0] imm,
  input [63:0] pc_i,

  output [63:0] res,
  output valid_o
);
/*verilator no_inline_module*/ 
  wire op_addw/*verilator public_flat*/ ,op_addiw/*verilator public_flat*/ ,op_subw/*verilator public_flat*/ ,op_add/*verilator public_flat*/ ,op_addi/*verilator public_flat*/ ,op_sub/*verilator public_flat*/ ,op_auipc/*verilator public_flat*/ ;
  assign {op_addw,op_addiw,op_subw,op_add,op_addi,
                          op_sub,op_auipc} = op;

  // wire [63:0] src1_w = $signed(src1);
  // wire [63:0] src2_w = $signed(src2);
  // wire [63:0] imm_w = $signed(imm);

  wire [63:0] src1_w /*verilator public_flat*/ = {{32{src1[31]}},src1[31:0]};
  wire [63:0] src2_w /*verilator public_flat*/ = {{32{src2[31]}},src2[31:0]};
  wire [63:0] imm_w /*verilator public_flat*/ = {{32{imm[31]}},imm[31:0]};

  wire [63:0] op_val_1 /*verilator public_flat*/ = ({64{op_addw|op_addiw|op_subw}}&src1_w) | ({64{op_add|op_addi|op_sub}}&src1) | ({64{op_auipc}}&pc_i);
  wire [63:0] op_val_2 /*verilator public_flat*/ = ({64{op_addw|op_subw}}&src2_w) | ({64{op_addiw}}&imm_w) | ({64{op_add|op_sub}}&src2) | ({64{op_addi|op_auipc}}&imm) ;

  wire sub /*verilator public_flat*/ = op_sub|op_subw;
  wire [63:0] mid_val_1 /*verilator public_flat*/ = {64{sub}}&((~op_val_2)+64'b1);
  wire [63:0] mid_val_2 /*verilator public_flat*/ = ({64{!sub}}&op_val_2);
  wire [63:0] res_mid /*verilator public_flat*/ = op_val_1 + ( mid_val_1 | mid_val_2);

  assign res = {{32{op_addiw|op_addw|op_subw}}&{32{res_mid[31]}} | {32{op_addi|op_add|op_sub|op_auipc}}&res_mid[63:32],res_mid[31:0]};
  assign valid_o = |op;
endmodule
